RPG Map
Want to make a world for your 2D RPG? Keep reading... Prerequisites: # Knowledge of a language # Ability to draw images with your language/API # Desire to make an RPG # Pulse Introduction This tutorial is intended for beginners. However you do need to be familiar with your preferred language and also must know already how to draw images, like bitmaps. Not everything is spelled out in this tutorial, such as where to place the code. This is because it's totally up to you. All you need to know is the concept. Lets begin. The Map If you don't know already, a map is the game world and the game world is the map. The map makes up the place your character runs around in. In this tutorial we're going to make a generic map system. You'll see that a map is nothing more than a grid, or 2D array, of tiles which will be represented like this illustration: So now you understand that a tile, or square, is the building block of a map. Now we need to represent this stuff with code, starting with the building block: TILE structure u : integer v : integer blocked : boolean This User Defined Type (UDT) holds all the properties we need for each tile. However u'' and ''v do NOT represent the tile's position! It's very important to understand this; u'' and ''v represent which part of our tiles bitmap is going to be drawn for this tile. Blocked is the property of the tile that tells us whether the characters can walk over that tile or not. We've represented the tile, now lets represent the map grid with a two-dimensional array: MapWidth = 80 MapHeight = 80 MapMapWidth,MapHeight : TILE // Declare this globally This is our map. Each tile's X and Y position on the map corresponds to where the tile is located at inside the array MapX,Y. You need to know some more information before we continue. Each tile we're using in this example is 32 x 32 pixels. The resolution we're running at is 640 x 480 pixels. Again, for the sake of demonstration, we're going to use constants because it's easier to read and understand than using magic numbers. TileWidth = 32 TileHeight = 32 ResolutionWidth = 640 ResolutionHeight = 480 x : integer y : integer r : RECT // Defines the area of the bitmap being drawn For x = 0 to ResolutionWidth / TileWidth For y = 0 to ResolutionHeight / TileHeight r.Left = Mapx,y.u r.Top = Mapx,y.v r.Right = r.Left + TileWidth r.Bottom = r.Top + TileHeight Draw(x * TileWidth, y * TileHeight, r) //...^ X position & ^ Y position where the portion of the bitmap ® is drawn Next y Next x Cool, isn't it? But wait a minute. We're only seeing a small region of our map, whats up with that? We'll have to 'scroll' the map (move it around) in order to explore it. We do this by using a camera or also called a point of view. Scrolling the map The camera system is nothing more than a point from which we begin to draw our map. It may be difficult to visualize at first, so I painted a pretty picture to show you: To represent the camera we use exactly what it is, a point (though technically it's a rectangle, all we need is the top left corner; a single point): POINT structure x : integer y : integer Camera : POINT We only draw the tiles that are within the camera's view (the rectangle). Now we can draw our map based on where our camera is at. An important thing to remember is that when you draw your tiles in your game while using the camera, you must always subtract the camera's x'' and ''y values from the x'' and ''y values of the object. The reason for this is that we want to always start at (0,0), the top left of our screen. Otherwise our tiles would be drawn with an offset equal to the camera's x'' and ''y values instead of from the origin. The map should move, not the screen. Let's do it: TileWidth = 32 TileHeight = 32 ResolutionWidth = 640 ResolutionHeight = 480 x : integer y : integer r : RECT For x = Camera.x / TileWidth to Camera.x / TileWidth + ResolutionWidth / TileWidth For y = Camera.y / TileHeight to Camera.y / TileHeight + ResolutionHeight / TileHeight r.Left = Mapx,y.u r.Top = Mapx,y.v r.Right = r.Left + TileWidth r.Bottom = r.Top + TileHeight Draw(x * TileWidth - Camera.x, y * TileHeight - Camera.y, r) Next y Next x Move your camera around in realtime. Nifty huh? But wait, you might have a problem: You've copied the code above letter for letter, with exception to naming of the variables and objects. Why aren't the tile's being drawn by the edges of the screen when I move the camera? That's because DirectDraw will only display blits that are totally onscreen. Yeah, that kinda sucks. But good news, we get around this by clipping the rectangle before using it to draw with. See clipping. If that wasn't your problem, then perhaps this is: You're escaping the bounds of your map array. Easy fix. You have to add restrictions to where your camera is allowed to be (ie keep it from trying to leave our map). This means we can't attempt to blit tiles that don't exist e.g. when the camera position's values are negative or greater than the map's dimensions, it's going to try to draw tiles that our map array doesn't even have! We apply these restrictions with a few conditionals before drawing. If Camera.x < 0 Then Camera.x = 0 If Camera.x + ResolutionWidth > MapWidth * TileWidth Then Camera.x = MapWidth * TileWidth - ResolutionWidth If Camera.y < 0 Then Camera.y = 0 If Camera.y + ResolutionHeight > MapHeight * TileHeight Then Camera.y = MapHeight * TileHeight - ResolutionHeight // Now drawing code... Didn't have either of those two problems? Pat yourself on the back. Have a different problem you encountered? Sucks to be you, this tutorial is finished. See the forum. Ready for the next level? Maybe you'd like to read about saving maps to files.